﻿// Date: 29.09.11

// Revision 2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NOVA.Components.Move;
using NOVA.Scenery;
using Microsoft.Xna.Framework;

namespace NOVA.ScreenManagement.BaseScreens
{
    public class PSMoveCalibrationScreen : GameplayScreen
    {
        PSMoveCalibration m_calibration;

        float pauseAlpha;

        bool m_bModelCreated;

        CapsuleObject box;

        GameScreen m_lastScreen;
        GameScreen m_nextScreen;

        public PSMoveCalibrationScreen(GameScreen lastScreen, GameScreen nextScreen) : base() 
        {
            m_lastScreen = lastScreen;
            m_nextScreen = nextScreen;
            m_bModelCreated = false;
        }

        public override void LoadContent()
        {
            base.LoadContent();

            // On pause, go back to the main menu
            OnPause += delegate
            {
                //this.ScreenManager.Game.Components.Remove(m_calibration);
                LoadingScreen.Load(ScreenManager, false, null, m_lastScreen);
            };

            // once the load has finished, we use ResetElapsedTime to tell the game's
            // timing mechanism that we have just finished a very long frame, and that
            // it should not try to catch up.
            ScreenManager.Game.ResetElapsedTime();
        }

        public override void Initialize()
        {
            base.Initialize();

            Scene.EnableLighting = true;
            Scene.ShowBoundingBoxes = true;
            Scene.RenderType = RenderType.SimpleRenderer;//MultiPass;

            CameraObject cam = new CameraObject(new Vector3(2, 10, 10), Vector3.Zero);
            Scene.Camera = cam;

            box = new CapsuleObject(Vector3.Zero, 1f, 5f, 10, 0f);//new BoxObject(Vector3.One * 500, Vector3.One, 0f);

            m_calibration = new PSMoveCalibration(ScreenManager.Game);

            m_calibration.Initialize();
        }

        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, false);

            m_calibration.Update(gameTime);

            if (!m_bModelCreated)
            {
                if (m_calibration.currentState == CalibrationState.Calibrated)
                {                    
                    Scene.Add(box);
                    m_bModelCreated = true;
                }
            }
            else
            {
                Vector3 vec1 = Vector3.Zero, vec2 = Vector3.Zero;

                int iX = (int)(m_calibration.ScreenPosition.X * Scene.Game.Window.ClientBounds.Width);
                int iY = (int)(m_calibration.ScreenPosition.Y * Scene.Game.Window.ClientBounds.Height);

                if (iX > 0 && iY > 0 && iX < Scene.Game.Window.ClientBounds.Width && iY < Scene.Game.Window.ClientBounds.Height)
                {
                    // Pay attention to the current camera view
                    Matrix viewMatrix = /*Scene.Camera.CameraTransformation */ Scene.Camera.ViewMatrix;

                    //// Convert the position vector from screen to world space -> 2D to 3D conversion
                    //Vector3 trans = Scene.Game.GraphicsDevice.Viewport.Unproject(new Vector3(iX, iY, 0),
                    //                                            Scene.Camera.ProjectionMatrix,
                    //                                            viewMatrix,
                    //                                            Matrix.Identity);

                    // Convert the position vector from screen to world space -> 2D to 3D conversion
                    vec1 = ScreenManager.Game.GraphicsDevice.Viewport.Unproject(new Vector3(iX, iY, 0),
                                Scene.Camera.ProjectionMatrix, viewMatrix, Matrix.Identity);
                    vec2 = ScreenManager.Game.GraphicsDevice.Viewport.Unproject(new Vector3(iX, iY, 1),
                                Scene.Camera.ProjectionMatrix, viewMatrix, Matrix.Identity);


                    // Use the distance to scale the vector
                    //Vector3 m_position = Vector3.Multiply(trans, m_calibration.imgProc.Distance/*temp.Z*/);

                    //// Assign the new translation to the model
                    ////cyl.Position = m_position;//m_trans.Translation = m_position;
                    //cyl.MoveToPosition(m_position);

                    Plane plane = new Plane(Vector3.Backward, 0f);// + m_kinect.HandPosition.Z*100f);

                    Vector3 dir = vec2 - vec1;
                    dir.Normalize();
                    Ray ray = new Ray(vec1, dir);
                    float? position = ray.Intersects(plane);

                    if (position.HasValue)
                    {
                        Vector3 pos = ray.Position + ray.Direction * position.Value;
                        box.Position = pos;
                    }

                    box.Orientation = m_calibration.Orientation;

                    if (m_calibration.moveController.psButtons.MOVE_CROSS_BUTTON)
                        LoadingScreen.Load(ScreenManager, true, ControllingPlayer, m_nextScreen);
                }
            }
        }

        public override void Draw(GameTime gameTime)
        {
            Scene.BackgroundTexture = m_calibration.GetCameraImage();
            base.Draw(gameTime);
        }

        public override void Dispose()
        {
            m_calibration.Dispose();

            base.Dispose();
        }
    }
}
